package o2o.config.dao;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.jinyou.utils.common.JsonUtils;
import com.jinyou.utils.common.ObjectUtils;
import com.jinyou.utils.common.ValidateUtil;
import com.mongodb.*;
import o2o.config.init.AutoWiredClass;
import org.apache.log4j.Logger;
import org.springframework.beans.BeanUtils;

import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.net.UnknownHostException;
import java.util.*;

/**
 * 类名： MongoDBDaoImpl 包名： com.newsTest.dao.impl 作者： Jahnke 时间：2016年3月9日11:21:30
 * 描述： MongoDB的方法
 */
public class MongoDaoImpl {
    Logger logger = Logger.getLogger(MongoDao.class);

    private static String url = "";
    private static int port;
    private static String username;
    private static String password;


    static {
        url = AutoWiredClass.mongoProperties2.getUrl();
        port = AutoWiredClass.mongoProperties2.getPort();
        username = AutoWiredClass.mongoProperties2.getUsername();
        password = AutoWiredClass.mongoProperties2.getPassword();
    }

    // 类初始化时，自行实例化，饿汉式单例模式
    private static final MongoDaoImpl mongoDBDaoImpl = new MongoDaoImpl();

    /**
     * MongoClient的实例代表数据库连接池，是线程安全的，可以被多线程共享，客户端在多线程条件下仅维持一个实例即可
     * Mongo是非线程安全的，目前mongodb API中已经建议用MongoClient替代Mongo
     */
    private MongoClient mongoClient = null;

    private MongoDaoImpl() {
        if (mongoClient == null) {
            MongoClientOptions.Builder build = new MongoClientOptions.Builder();
            build.connectionsPerHost(50); // 与目标数据库能够建立的最大connection数量为50
            build.autoConnectRetry(true); // 自动重连数据库启动
            build.threadsAllowedToBlockForConnectionMultiplier(50); // 如果当前所有的connection都在使用中，则每个connection上可以有50个线程排队等待
            /*
             * 一个线程访问数据库的时候，在成功获取到一个可用数据库连接之前的最长等待时间为2分钟
             * 这里比较危险，如果超过maxWaitTime都没有获取到这个连接的话，该线程就会抛出Exception
             * 故这里设置的maxWaitTime应该足够大，以免由于排队线程过多造成的数据库访问失败
             */
            build.maxWaitTime(1000 * 60 * 2);
            build.connectTimeout(1000 * 60 * 1); // 与数据库建立连接的timeout设置为1分钟

            MongoClientOptions myOptions = build.build();
            try {
                // 数据库连接实例
                mongoClient = new MongoClient(new ServerAddress(url, port),
                        myOptions);
            } catch (UnknownHostException e) {
                // TODO 这里写异常处理的代码
                e.printStackTrace();
            } catch (MongoException e) {
                e.printStackTrace();
            }

        }
    }


    public static MongoDaoImpl getInstance() {
        return mongoDBDaoImpl;
    }

    public DB getDb(String dbName) {
        return mongoClient.getDB(dbName);
    }

    public DBCollection getCollection(String dbName, String collectionName) {
        return mongoClient.getDB(dbName).getCollection(collectionName);
    }

    public boolean insert(String dbName, String collectionName,
                          Map<String, Object> map) {
        DB db = null;
        DBCollection dbCollection = null;
        WriteResult result = null;
        String resultString = null;
        if (map != null && map != null) {
            db = mongoClient.getDB(dbName); // 获取数据库实例
            dbCollection = db.getCollection(collectionName); // 获取数据库中指定的collection集合
            BasicDBObject insertObj = new BasicDBObject();
            for (String key : map.keySet()) {
                insertObj.put(key, map.get(key));
            }
            try {
                result = dbCollection.insert(insertObj);
                resultString = result.getError();
            } catch (Exception e) {
                // TODO: handle exception
                e.printStackTrace();
            } finally {
                if (null != db) {
                    db.requestDone(); // 请求结束后关闭db
                }
            }
            return (resultString != null) ? false : true;
        }
        return false;
    }

    public boolean delete(String dbName, String collectionName,
                          Map<String, Object> map) {
        DB db = null;
        DBCollection dbCollection = null;
        if (map != null && map != null) {
            try {
                db = mongoClient.getDB(dbName); // 获取指定的数据库
                if (null == db || !db.collectionExists(collectionName)) {
                    return true;
                }
                dbCollection = db.getCollection(collectionName); // 获取指定的collectionName集合
                if (null == dbCollection || dbCollection.count() < 1) {
                    return true;
                }
                BasicDBObject doc = new BasicDBObject(); // 构建删除条件
                WriteResult result = null; // 删除返回结果
                String resultString = null;
                for (String key : map.keySet()) {
                    doc.put(key, map.get(key));
                }
                result = dbCollection.remove(doc); // 执行删除操作
                resultString = result.getError();
                if (null != db) {
                    try {
                        db.requestDone(); // 请求结束后关闭db
                        db = null;
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
                return (resultString != null) ? false : true; // 根据删除执行结果进行判断后返回结果
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                if (null != db) {
                    db.requestDone(); // 关闭db
                    db = null;
                }
            }
        }
        return false;
    }

    // 删除数据，不用collectionName,获取所有的，只要含有就删除
    public boolean delete(String dbName, Map<String, Object> map) {
        if (map != null && map != null) {
            Set<String> set = null;
            DB db = null;
            try {
                db = mongoClient.getDB(dbName); // 获取指定的数据库
                set = db.getCollectionNames();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                if (null != db) {
                    db.requestDone(); // 关闭db
                    db = null;
                }
            }
            if (null != set && set.size() > 0) {
                for (String colName : set) {
                    if (ValidateUtil.isNull(colName)) {
                        continue;
                    }

                    delete(dbName, colName, map);
                }
            }
        }
        return false;
    }

    public <T> List<T> find(Class<T> clazz, String dbName,
                            String collectionName, DBObject queryObj, int page, int size,
                            String orderBy, int order) {
        DB db = null;
        DBCollection dbCollection = null;
        DBCursor cursor = null;
        try {
            db = mongoClient.getDB(dbName); // 获取数据库实例

            dbCollection = db.getCollection(collectionName); // 获取数据库中指定的collection集合
            // 构建查询条件
            if (queryObj != null) {
                cursor = dbCollection.find(queryObj);
            } else {
                cursor = dbCollection.find();
            }
            if (orderBy != null && !orderBy.equals("")) {
                cursor = cursor.skip(page * size).limit(size)
                        .sort(new BasicDBObject(orderBy, ((order >= 0 ? 1 : -1)))); // 查询获取数据
            } else {
                cursor = cursor.skip(page * size).limit(size); // 查询获取数据
            }
            StringBuffer sb = new StringBuffer("["); // 定义stringbuffer
            while (cursor.hasNext()) {
                sb.append(cursor.next().toString()).append(",");
            }
            sb.append("]");
            String resStr = sb.toString();
            resStr = resStr.replace(",]", "]");
            JSONArray array = JSONArray.parseArray(resStr);
            List<T> list = null;
            if (array != null && !array.isEmpty()) {
                list = new ArrayList<>();
                for (int i = 0; i < array.size(); i++) {
                    array.getJSONObject(i).remove("_id");
                    list.add(JSONObject.parseObject(array.getString(i), clazz));
                }
            }
            return list;
        } catch (Exception e) {
            // TODO: handle exception
            e.printStackTrace();
        } finally {
            if (null != cursor) {
                cursor.close();
            }
            if (null != db) {
                db.requestDone(); // 关闭数据库请求
            }
        }
        return null;
    }

    public List<HashMap<String, Object>> find(String dbName,
                                              String collectionName, Map<String, Object> map, int num,
                                              String orderBy, int order) {
        DB db = null;
        DBCollection dbCollection = null;
        DBCursor cursor = null;
        try {
            db = mongoClient.getDB(dbName); // 获取数据库实例

            // TODO:可以添加数据库访问权限
             boolean auth = db.authenticate(username, password.toCharArray());
            // //输入用户名和密码。获取权限

            dbCollection = db.getCollection(collectionName); // 获取数据库中指定的collection集合
            // 构建查询条件
            if (map != null && !map.isEmpty()) {
                BasicDBObject queryObj = new BasicDBObject();
                Set<String> keySet = map.keySet();
                for (String key : map.keySet()) {
                    queryObj.put(key, map.get(key));
                }
                if (orderBy != null && !orderBy.equals("")) {
                    cursor = dbCollection.find(queryObj).limit(num)
                            .sort(new BasicDBObject(orderBy, ((order >= 0 ? 1 : -1)))); // 查询获取数据
                } else {
                    cursor = dbCollection.find(queryObj).limit(num); // 查询获取数据
                }
            } else {
                if (orderBy != null && !orderBy.equals("")) {
                    cursor = dbCollection.find().limit(num).sort(
                            new BasicDBObject(orderBy, (order >= 0 ? 1 : -1))); // 查询获取数据
                } else {
                    cursor = dbCollection.find().limit(num);
                }
            }
            StringBuffer sb = new StringBuffer("["); // 定义stringbuffer
            while (cursor.hasNext()) {
                sb.append(cursor.next().toString()).append(",");
            }
            sb.append("]");
            String resStr = sb.toString();
            resStr = resStr.replace(",]", "]");
            List<HashMap<String, Object>> list = JsonUtils.jsonToListmap(resStr);
            return list;
        } catch (Exception e) {
            // TODO: handle exception
            e.printStackTrace();
        } finally {
            if (null != cursor) {
                cursor.close();
            }
            if (null != db) {
                db.requestDone(); // 关闭数据库请求
            }
        }
        return null;
    }

    public List<HashMap<String, Object>> finds(String dbName,
                                               String collectionName, Map<String, Object> map, int num, int skip, BasicDBObject sort) {
        DB db = null;
        DBCollection dbCollection = null;
        DBCursor cursor = null;
        try {
            db = mongoClient.getDB(dbName); // 获取数据库实例

            // TODO:可以添加数据库访问权限
             boolean auth = db.authenticate(username, password.toCharArray());
            // //输入用户名和密码。获取权限

            dbCollection = db.getCollection(collectionName); // 获取数据库中指定的collection集合
            // 构建查询条件
            if (map != null && !map.isEmpty()) {
                BasicDBObject queryObj = new BasicDBObject();
                Set<String> keySet = map.keySet();
                for (String key : map.keySet()) {
                    queryObj.put(key, map.get(key));
                }
                if (sort != null) {
                    cursor = dbCollection.find(queryObj).limit(num).skip(skip)
                            .sort(sort); // 查询获取数据
                } else {
                    cursor = dbCollection.find(queryObj).limit(num).skip(skip); // 查询获取数据
                }
            } else {
                if (sort != null) {
                    cursor = dbCollection.find().limit(num).skip(skip).sort(sort); // 查询获取数据
                } else {
                    cursor = dbCollection.find().limit(num).skip(skip);
                }
            }
            int count = 0;

            StringBuffer sb = new StringBuffer("["); // 定义stringbuffer
            while (cursor.hasNext()) {
                sb.append(cursor.next().toString()).append(",");
            }
            sb.append("]");
            String resStr = sb.toString();
            resStr = resStr.replace(",]", "]");
            List<HashMap<String, Object>> list = JsonUtils.jsonToListmap(resStr);
            return list;
        } catch (Exception e) {
            // TODO: handle exception
            e.printStackTrace();
        } finally {
            if (null != cursor) {
                cursor.close();
            }
            if (null != db) {
                db.requestDone(); // 关闭数据库请求
            }
        }
        return null;
    }

    public List<HashMap<String, Object>> finds(String dbName,
                                               String collectionName, Map<String, Object> map, int num, BasicDBObject sort) {
        DB db = null;
        DBCollection dbCollection = null;
        DBCursor cursor = null;
        try {
            db = mongoClient.getDB(dbName); // 获取数据库实例

            // TODO:可以添加数据库访问权限
             boolean auth = db.authenticate(username, password.toCharArray());
            // //输入用户名和密码。获取权限

            dbCollection = db.getCollection(collectionName); // 获取数据库中指定的collection集合
            // 构建查询条件
            if (map != null && !map.isEmpty()) {
                BasicDBObject queryObj = new BasicDBObject();
                Set<String> keySet = map.keySet();
                for (String key : map.keySet()) {
                    queryObj.put(key, map.get(key));
                }
                if (sort != null) {
                    cursor = dbCollection.find(queryObj).limit(num)
                            .sort(sort); // 查询获取数据
                } else {
                    cursor = dbCollection.find(queryObj).limit(num); // 查询获取数据
                }
            } else {
                if (sort != null) {
                    cursor = dbCollection.find().limit(num).sort(sort); // 查询获取数据
                } else {
                    cursor = dbCollection.find().limit(num);
                }
            }
            int count = 0;

            StringBuffer sb = new StringBuffer("["); // 定义stringbuffer
            while (cursor.hasNext()) {
                sb.append(cursor.next().toString()).append(",");
            }
            sb.append("]");
            String resStr = sb.toString();
            resStr = resStr.replace(",]", "]");
            List<HashMap<String, Object>> list = JsonUtils.jsonToListmap(resStr);
            return list;
        } catch (Exception e) {
            // TODO: handle exception
            e.printStackTrace();
        } finally {
            if (null != cursor) {
                cursor.close();
            }
            if (null != db) {
                db.requestDone(); // 关闭数据库请求
            }
        }
        return null;
    }

    public long count(String dbName, String collectionName, Map<String, Object> map) {
        DB db = null;
        DBCollection dbCollection = null;
        try {
            db = this.mongoClient.getDB(dbName);
            dbCollection = db.getCollection(collectionName);
            BasicDBObject doc = new BasicDBObject();
            WriteResult result = null;
            String resultString = null;
            if ((map != null) && (map != null)) {
                for (String key : map.keySet()) {
                    doc.put(key, map.get(key));
                }
            }
            long count = dbCollection.count(doc);
            long l1 = count;
            return l1;
        } catch (Exception e) {
            e.printStackTrace();
            if (null != db) {
                db.requestDone();
                db = null;
            }
        } finally {
            if (null != db) {
                db.requestDone();
                db = null;
            }
        }
        return 0L;
    }

    public List<HashMap<String, Object>> find(String dbName,
                                              String collectionName, Map<String, Object> map, int num) {
        return find(dbName, collectionName, map, num, null, 1);
    }

    public List<HashMap<String, Object>> find(String dbName,
                                              String collectionName, int num, String orderBy, int order) {
        return find(dbName, collectionName, null, num, orderBy, order);
    }

    public List<HashMap<String, Object>> find(String dbName,
                                              String collectionName, int num) {
        return find(dbName, collectionName, null, num, null, 1);
    }

    public boolean update(String dbName, String collectionName,
                          DBObject oldValue, DBObject newValue) {
        return update(dbName, collectionName, oldValue, newValue, false);
    }

    public boolean update(String dbName, String collectionName,
                          DBObject oldValue, DBObject newValue, boolean upsert) {
        DB db = null;
        DBCollection dbCollection = null;
        WriteResult result = null;
        String resultString = null;
        if (oldValue != null && oldValue.equals(newValue)) {
            return true;
        } else {
            try {
                db = mongoClient.getDB(dbName); // 获取数据库实例
                dbCollection = db.getCollection(collectionName); // 获取数据库中指定的collection集合
                result = dbCollection.update(oldValue, newValue, upsert, false);
                resultString = result.getError();
                return (resultString != null) ? false : true;
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                if (null != db) {
                    db.requestDone(); // 关闭db
                    db = null;
                }
            }
        }
        return false;
    }

    public boolean updateT(String dbName, String collectionName,
                           DBObject oldValue, DBObject newValue) {
        DB db = null;
        DBCollection dbCollection = null;
        WriteResult result = null;
        String resultString = null;
        if (oldValue != null && oldValue.equals(newValue)) {
            return true;
        } else {
            try {
                db = mongoClient.getDB(dbName); // 获取数据库实例
                dbCollection = db.getCollection(collectionName); // 获取数据库中指定的collection集合
                result = dbCollection.update(oldValue, newValue, false, true);
                resultString = result.getError();
                return (resultString != null) ? false : true;
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                if (null != db) {
                    db.requestDone(); // 关闭db
                    db = null;
                }
            }
        }
        return false;
    }

    public boolean isExit(String dbName, String collectionName,
                          Map<String, Object> map) {
        DB db = null;
        DBCollection dbCollection = null;
        if (map != null && map != null) {
            try {
                db = mongoClient.getDB(dbName); // 获取数据库实例
                dbCollection = db.getCollection(collectionName); // 获取数据库中指定的collection集合
                BasicDBObject obj = new BasicDBObject(); // 构建查询条件
                for (String key : map.keySet()) {
                    obj.put(key, map.get(key));
                }
                if (dbCollection.count(obj) > 0) {
                    return true;
                } else {
                    return false;
                }
            } catch (Exception e) {
                // TODO: handle exception
                e.printStackTrace();
            } finally {
                if (null != db) {
                    db.requestDone(); // 关闭db
                    db = null;
                }
            }
        }
        return false;
    }

    public static BasicDBObject getDBBasic(Object obj) {
        if (obj != null) {
            BeanInfo beanInfo;
            BasicDBObject query = new BasicDBObject();
            try {
                beanInfo = Introspector.getBeanInfo(obj.getClass());
                PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
                for (PropertyDescriptor property : propertyDescriptors) {
                    String key = property.getName();
                    if (key.compareToIgnoreCase("class") == 0) {
                        continue;
                    }
                    Method getter = property.getReadMethod();
                    Object value = getter != null ? getter.invoke(obj) : "";
                    query.put(key, value);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            return query;
        } else {
            return null;
        }
    }

}
